﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
using System.Text;
using System.Data;
using System.Data.SqlClient;

using System.Runtime.InteropServices;
using System.Reflection;

/// <summary>
/// Summary description for Customer
/// </summary>
namespace Triax.Modules.Department
{
    public class DoiTuong
    {
        protected DataRow _DataRow = null;
        public DataRow DataRow
        {
            get
            {
                return _DataRow;
            }
            set
            {
                _DataRow = value;
            }
        }

        #region int id property
        public int id
        {
            get
            {
                if (_DataRow["id"] is int) return (int)_DataRow["id"];
                return 0;
            }
            set
            {
                _DataRow["id"] = value;
            }
        }
        #endregion

        public virtual void InsertToDB()
        {
            SqlConnection con = new SqlConnection(CommonLib.ConnectString);
            try
            {
                con.Open();
                SqlCommand cmd = con.CreateCommand();
                InsertToDB(cmd);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
        }
        
        public virtual void UpdateToDB()
        {
            SqlConnection con = new SqlConnection(CommonLib.ConnectString);
            try
            {
                con.Open();
                SqlCommand cmd = con.CreateCommand();
                UpdateToDB(cmd);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
        }

        public virtual void InsertToDB(SqlCommand cmd)
        {
            if (cmd.Connection.State != ConnectionState.Open) throw new Exception("Chưa mở connection");
            string values = ""; string listOfColumns = "";
            cmd.Parameters.Clear();
            foreach (DataColumn column in this.DataRow.Table.Columns)
            {
                if (!column.ColumnName.ToUpper().Equals("ID")) 
                {
                    values = values + "@" + column.ColumnName + ", ";
                    listOfColumns = listOfColumns + column.ColumnName + ", ";
                    cmd.Parameters.AddWithValue(column.ColumnName, this.DataRow[column.ColumnName]);
                }
            }

            if (values.EndsWith(", ")) values = values.Substring(0, values.Length - 2);
            if (listOfColumns.EndsWith(", ")) listOfColumns = listOfColumns.Substring(0, listOfColumns.Length - 2);

            cmd.CommandText = string.Format("INSERT INTO [{0}]({1}) output INSERTED.ID VALUES({2}); SELECT SCOPE_IDENTITY();",
                                                this.DataRow.Table.TableName, listOfColumns, values);
            int modified = (int)cmd.ExecuteScalar();
             
            if (this.DataRow.Table.Rows.IndexOf(this.DataRow) < 0) 
            {
                this.DataRow["id"] = (int)modified;
                //this.DataRow.Table.Rows.Add(this.DataRow);  //A Nam luôn query trực tiếp SQL nên k cho vào DataTable
            }
        }
        
        public virtual void UpdateToDB(SqlCommand cmd)
        {
            if (cmd.Connection.State != ConnectionState.Open) throw new Exception("Chưa mở connection");
            string values = "";
            cmd.Parameters.Clear();
            foreach (DataColumn column in this.DataRow.Table.Columns)
            {
                if (!column.ColumnName.ToUpper().Equals("ID")) 
                {
                    values += string.Format("{0} = @{0}, ", column.ColumnName);
                    if (this.DataRow[column.ColumnName] is Guid && (Guid)this.DataRow[column.ColumnName] == Guid.Empty)
                    {
                        cmd.Parameters.AddWithValue(column.ColumnName, DBNull.Value);
                    }
                    else
                    {
                        cmd.Parameters.AddWithValue(column.ColumnName, this.DataRow[column.ColumnName]);
                    }
                }
            }

            if (values.EndsWith(", ")) values = values.Substring(0, values.Length - 2);

            cmd.CommandText = string.Format("UPDATE [{0}] SET {1} WHERE ID = '{2}'",
                                                this.DataRow.Table.TableName,
                                                values,
                                                this.DataRow["ID"]);
            cmd.ExecuteNonQuery();
        }

        public virtual void DeleteFromDB()
        {
            SqlConnection con = new SqlConnection(CommonLib.ConnectString);
            try
            {
                con.Open();
                SqlCommand cmd = con.CreateCommand();
                cmd.CommandText = string.Format("DELETE FROM [{0}] WHERE ID = '{1}'",
                                                    this.DataRow.Table.TableName,
                                                    this.DataRow["ID"]);
                cmd.ExecuteNonQuery();
                _DataRow.Delete();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
        }
        public virtual void DeleteFromDB(SqlCommand cmd)
        {
            try
            {
                cmd.CommandText = string.Format("DELETE FROM [{0}] WHERE ID = '{1}'",
                                                    this.DataRow.Table.TableName,
                                                    this.DataRow["ID"]);
                cmd.ExecuteNonQuery();
                _DataRow.Delete();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                cmd.Connection.Close();
            }
        }

        public DoiTuong()
        {
            //_DataRow = dataRow;
            //if (this.ID == Guid.Empty) this.ID = CustomGuid.NewSequentialId();
        }
        public DoiTuong(DataRow dataRow)
        {
            _DataRow = dataRow;
        }
    }

    public abstract class DanhMucDoiTuong
    {
        #region TableName property
        public virtual string TableName
        {
            get
            {
                throw new Exception("Chưa khởi tạo tên bảng cho danh mục. Lỗi lập trình: cần overide TableName");
            }
        }
        #endregion

        #region DataTable property
        public DataSet _DataSet;
        public DataTable DataTable
        {
            get
            {
                if (_DataSet == null || _DataSet.Tables.Count == 0)
                {
                    _DataSet = new DataSet();
                    LoadFromDB();
                }
                return _DataSet.Tables[0];
            }
        }
        #endregion

        #region DataView property
        private DataView _DataView;
        public DataView DataView
        {
            get
            {
                return _DataView;
            }
            set
            {
                _DataView = value;
            }
        }
        #endregion

        public delegate void ChangeHandler();
        public event ChangeHandler Change;
        protected SqlDataAdapter _DataAdapter = new SqlDataAdapter();

        protected DanhMucDoiTuong()
        {
        }

        //Chỉ load 1 row để lấy được cấu trúc bảng
        public bool LoadFromDB()
        {
            SqlConnection con = new SqlConnection(CommonLib.ConnectString);
            try
            {
                SqlCommand cmd = con.CreateCommand();

                switch (TableName)
                {
                    case "KhoanMucSOP":
                        cmd.CommandText = string.Format("SELECT * FROM [{0}] ORDER BY ThuTuKhoanMuc", TableName);
                        break;
                    default:
                        cmd.CommandText = string.Format("SELECT * FROM [{0}]", TableName);
                        break;
                }

                _DataAdapter.SelectCommand = cmd;
                _DataSet.Clear();
                _DataAdapter.Fill(_DataSet, TableName);

                return true;
            }
            catch (SqlException sqlEx)
            {
                if (!sqlEx.Message.Contains("Login failed for user"))
                    return false;
            }
            catch (Exception ex)
            {
                if (!ex.Message.Contains("Login failed for user"))
                    return false;
            }
            finally
            {
                con.Close();
            }
            return true;
        }

        public void InsertToDB(DoiTuong doiTuong)
        {
            if (DataTable.Rows.IndexOf(doiTuong.DataRow) < 0) DataTable.Rows.Add(doiTuong.DataRow);
        }

        public void UpdateToDB()
        {
            try
            {
                SqlCommandBuilder commandBuilder = new SqlCommandBuilder((SqlDataAdapter)_DataAdapter);
                commandBuilder.DataAdapter.Update(_DataSet, TableName);
                this.DataTable.AcceptChanges();
                try
                {
                    if (Change != null) Change();
                }
                catch (Exception ex)
                {
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public int Count
        {
            get
            {
                return this.DataView.Count;
            }
        }
        protected DataRow[] GetDataRows(string filterExpression)
        {
            return DataTable.Select(filterExpression);
        }

        protected DataRow[] GetDataRows(string property, object value)
        {
            string filterExpression = "";
            if (value is string)
            {
                value = (value as string).Replace("'", "''");
                filterExpression = string.Format("{0} = '{1}'", property, value);
            }
            else if (value is Guid)
                filterExpression = string.Format("{0} = '{1}'", property, value);
            else
                filterExpression = string.Format("{0} = {1}", property, value);

            return DataTable.Select(filterExpression);
        }

        public static void ReloadAllDanhMuc()
        {
            try
            {

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        //Method tìm kiếm theo điều kiện
        public virtual List<DoiTuong> SearchByCon(string condition)
        {
            try
            {
                return null;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }

    public static class ExtensionUtility
    {
        /*Converts List To DataTable*/
        public static DataTable ToDataTable<TSource>(this IList<TSource> data)
        {
            DataTable dataTable = new DataTable(typeof(TSource).Name);
            PropertyInfo[] props = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo prop in props)
            {
                dataTable.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }

            foreach (TSource item in data)
            {
                var values = new object[props.Length];
                for (int i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }
                dataTable.Rows.Add(values);
            }
            return dataTable;
        }

        /*Converts DataTable To List*/
        public static List<TSource> ToList<TSource>(this DataTable dataTable) where TSource : new()
        {
            var dataList = new List<TSource>();

            const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
            var objFieldNames = (from PropertyInfo aProp in typeof(TSource).GetProperties(flags)
                                 select new { Name = aProp.Name, Type = Nullable.GetUnderlyingType(aProp.PropertyType) ?? aProp.PropertyType }).ToList();
            var dataTblFieldNames = (from DataColumn aHeader in dataTable.Columns
                                     select new { Name = aHeader.ColumnName, Type = aHeader.DataType }).ToList();
            var commonFields = objFieldNames.Intersect(dataTblFieldNames).ToList();

            foreach (DataRow dataRow in dataTable.AsEnumerable().ToList())
            {
                var aTSource = new TSource();
                foreach (var aField in commonFields)
                {
                    PropertyInfo propertyInfos = aTSource.GetType().GetProperty(aField.Name);
                    var value = (dataRow[aField.Name] == DBNull.Value) ? null : dataRow[aField.Name]; //if database field is nullable
                    propertyInfos.SetValue(aTSource, value, null);
                }
                dataList.Add(aTSource);
            }
            return dataList;
        }
    }
}